#include <iostream>
#include <functional>
#include <ctime>
#include <cassert>
#include <string>
#include <vector>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

class channal
{
public:
    channal(int fd, pid_t id, int num)
        : _fd(fd), _id(id), _name("channal-" + to_string(num))
    {
    }

    int _fd;
    pid_t _id;
    string _name;
};

void download()
{
    cout << "我是一个下载任务，我的pid是：" << getpid() << endl;
}

void printlog()
{
    cout << "我是一个打印日志任务，我的pid是：" << getpid() << endl;
}

void compressedfile()
{
    cout << "我是一个压缩文件任务，我的pid是：" << getpid() << endl;
}

using task_t = function<void()>;

class task
{
public:
    task()
    {
        _messions.push_back(download);
        _messions.push_back(printlog);
        _messions.push_back(compressedfile);

        srand((unsigned)time(nullptr));
    }

    task_t gettask(int num)
    {
        assert(num >= 0 && num < _messions.size());

        return _messions[num];
    }

    int gettasksize()
    {
        return _messions.size();
    }

    string gettaskname(int num)
    {
        assert(num >= 0 && num < _messions.size());

        switch (num)
        {
        case _download:
            return "_download";
            break;
        case _printlog:
            return "_printlog";
            break;
        case _compressedfile:
            return "_compressedfile";
            break;

        default:
            return "";
            break;
        }
    }

private:
    static const int _download = 0;
    static const int _printlog = 1;
    static const int _compressedfile = 2;

    vector<task_t> _messions;
};

task task_list;

int main()
{
    vector<channal> channals;
    vector<int> tmp;
    for (int i = 0; i < 5; i++)
    {

        // 创建与子进程通信的管道(信道)
        int pipefd[2];
        int piperet = pipe(pipefd);
        if (piperet < 0)
        {
            cout << "erron: " << errno << " error: " << strerror(errno) << endl;
            return 1;
        }

        // 创建子进程，建立信道
        pid_t id = fork();
        if (id < 0)
        {
            cout << "erron: " << errno << " error: " << strerror(errno) << endl;
            return 1;
        }
        else if (id == 0)
        {
            // 子进程
            if (!tmp.empty())
            {
                for (int i = 0; i < tmp.size(); i++)
                {
                    close(tmp[i]);
                }
            }

            close(pipefd[1]); // 关闭写端
            while (true)
            {
                int mession = 0;
                ssize_t n = read(pipefd[0], &mession, sizeof(mession));
                if (n < 0)
                {
                    cout << "erron: " << errno << " error: " << strerror(errno) << endl;
                    exit(1);
                }
                else if (n != 4)
                    break;
                else
                {
                    // 执行任务
                    task_list.gettask(mession)();
                }
            }

            exit(0);
        }
        // 父进程
        close(pipefd[0]); // 关闭读端
        channals.push_back({pipefd[1], id, i});
        tmp.push_back(pipefd[1]);
    }

    // 父进程就可以开始给子进程分配任务了
    int pos = 0;
    int x = 0;
    while (true)
    {
        pos %= channals.size();
        int mession = rand() % task_list.gettasksize();
        ssize_t n = write(channals[pos]._fd, &mession, sizeof(mession));
        cout << "分配给信道：" << channals[pos]._name << "任务：" << task_list.gettaskname(mession) << "它的pid是：" << channals[pos]._id << endl;
        if (n < 0)
        {
            cout << "erron: " << errno << " error: " << strerror(errno) << endl;
            return 1;
        }
        sleep(1);
        pos++;
        x++;
        if (x == 10)
        {
            break;
        }
    }

    // // 回收子进程
    // for (int i = 0; i < channals.size(); i++)
    // {
    //     close(channals[i]._fd);
    // }

    // for (int i = 0; i < channals.size(); i++)
    // {
    //     pid_t retpid = waitpid(channals[i]._id, nullptr, 0);
    //     if (retpid == channals[i]._id)
    //     {
    //         cout << "回收子进程成功：" << retpid << endl;
    //     }
    // }
    // for (int i = channals.size() - 1; i >= 0; i--)
    // {
    //     close(channals[i]._fd);
    //     pid_t retpid = waitpid(channals[i]._id, nullptr, 0);
    //     if (retpid == channals[i]._id)
    //     {
    //         cout << "回收子进程成功：" << retpid << endl;
    //     }
    // }

    for (int i = 0; i < channals.size(); i++)
    {
        close(channals[i]._fd);
        pid_t retpid = waitpid(channals[i]._id, nullptr, 0);
        if (retpid == channals[i]._id)
        {
            cout << "回收子进程成功：" << retpid << endl;
        }
    }

    return 0;
}